package com.eian.boot.common.id.obfuscator;

/**
 * ID混淆工具（弱可读性）
 * 通过位运算实现ID的混淆和反混淆，用于订单号等需要弱可读性的场景
 *
 * @author alex.meng
 */
public class IdObfuscator {

    /**
     * 混淆密钥
     */
    private static final long OBFUSCATE_KEY = 0x5A7F3B9C4E1D6F82L;

    /**
     * 位置打乱映射表（将64位的每个位映射到新位置）
     */
    private static final int[] SHUFFLE_MAP = {
            31, 0, 15, 47, 23, 8, 39, 55,
            7, 24, 51, 16, 3, 40, 59, 12,
            27, 4, 43, 19, 63, 11, 35, 52,
            28, 20, 48, 36, 56, 44, 60, 1,
            13, 32, 5, 21, 49, 9, 37, 57,
            2, 17, 33, 45, 25, 53, 10, 41,
            29, 6, 18, 61, 14, 38, 50, 26,
            46, 34, 54, 22, 58, 42, 62, 30
    };

    /**
     * 反向映射表（用于反混淆）
     */
    private static final int[] REVERSE_SHUFFLE_MAP = new int[64];

    static {
        // 初始化反向映射表
        for (int i = 0; i < 64; i++) {
            REVERSE_SHUFFLE_MAP[SHUFFLE_MAP[i]] = i;
        }
    }

    /**
     * 混淆ID
     *
     * @param id 原始ID
     * @return 混淆后的ID
     */
    public long obfuscate(long id) {
        // 先异或密钥
        long xored = id ^ OBFUSCATE_KEY;

        // 再进行位置打乱
        return shuffleBits(xored, SHUFFLE_MAP);
    }

    /**
     * 反混淆ID
     *
     * @param obfuscatedId 混淆后的ID
     * @return 原始ID
     */
    public long deobfuscate(long obfuscatedId) {
        // 先反向位置打乱
        long unshuffled = shuffleBits(obfuscatedId, REVERSE_SHUFFLE_MAP);

        // 再异或密钥恢复
        return unshuffled ^ OBFUSCATE_KEY;
    }

    /**
     * 混淆ID（字符串形式）
     *
     * @param id 原始ID
     * @return 混淆后的ID字符串
     */
    public String obfuscateStr(long id) {
        return String.valueOf(obfuscate(id));
    }

    /**
     * 反混淆ID（字符串形式）
     *
     * @param obfuscatedIdStr 混淆后的ID字符串
     * @return 原始ID
     */
    public long deobfuscateStr(String obfuscatedIdStr) {
        return deobfuscate(Long.parseLong(obfuscatedIdStr));
    }

    /**
     * 位置打乱
     *
     * @param value 原始值
     * @param map   映射表
     * @return 打乱后的值
     */
    private long shuffleBits(long value, int[] map) {
        long result = 0L;
        for (int i = 0; i < 64; i++) {
            // 获取第i位的值
            long bit = (value >> i) & 1L;
            // 放到新位置
            result |= (bit << map[i]);
        }
        return result;
    }
}

